#include "relic.h"
#include "sqft_conf.h"
#include "relic_bench.h"
#include <time.h>


void perf_tests() {
	bn_t a, b, c, d;
	
	bn_null(a);
	bn_null(b);
	bn_null(c);
	bn_null(d);
	
	bn_new(a);
	bn_new(b);
	bn_new(c);
	bn_new(d);
	
	BENCH_BEGIN("bn_add") {
		bn_rand(a, BN_POS, BN_BITS);
		bn_rand(b, BN_POS, BN_BITS);
		BENCH_ADD(bn_add(c, a, b));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_sub") {
		bn_rand(a, BN_POS, BN_BITS);
		bn_rand(b, BN_POS, BN_BITS);
		BENCH_ADD(bn_sub(c, a, b));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_mul_basic") {
		bn_rand(a, BN_POS, BN_BITS);
		bn_rand(b, BN_POS, BN_BITS);
		BENCH_ADD(bn_mul_basic(c, a, b));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_mul_karat") {
		bn_rand(a, BN_POS, BN_BITS);
		bn_rand(b, BN_POS, BN_BITS);
		BENCH_ADD(bn_mul_karat(c, a, b));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_mul_comba") {
		bn_rand(a, BN_POS, BN_BITS);
		bn_rand(b, BN_POS, BN_BITS);
		BENCH_ADD(bn_mul_comba(c, a, b));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_sqr") {
		bn_rand(a, BN_POS, BN_BITS);
		BENCH_ADD(bn_sqr(c, a));
	}
	BENCH_END;
	
	
	bn_gen_prime(c, BN_BITS);
	
	BENCH_BEGIN("bn_mod") {
		bn_rand(a, BN_POS, BN_BITS);
		bn_sqr(a, a);
		BENCH_ADD(bn_mod(b, a, c));
	}
	BENCH_END;
	
	bn_rand(a, BN_POS, BN_BITS);
	bn_rand(b, BN_POS, BN_BITS);
	
	BENCH_ONCE("bn_mxp_basic", bn_mxp_basic(d, a, c, c));
	BENCH_ONCE("bn_mxp_slide", bn_mxp_slide(d, a, b, c));
	BENCH_ONCE("bn_mxp_monty", bn_mxp_monty(d, a, b, c));
	
	bn_gen_prime(b, BN_BITS);
	BENCH_BEGIN("bn_smb_jac") {
		bn_rand(a, BN_POS, BN_BITS);
		BENCH_ADD(bn_smb_jac(c, a, b));
	}
	BENCH_END;
	
	BENCH_BEGIN("zero mod") {
		bn_zero(a);
		BENCH_ADD(bn_mod(c, a, b));
	}
	BENCH_END;
	
	bn_free(a);
	bn_free(b);
	bn_free(c);
	bn_free(d);
}

void pol() {
	bn_t t, p;
	bn_t a[2], b[2], c[2], d[2], m[2];
	
	bn_null(t);
	bn_null(p);
	bn_pol_null(a);
	bn_pol_null(b);
	bn_pol_null(c);
	bn_pol_null(d);
	bn_pol_null(m);
	
	bn_new(t);
	bn_new(p);
	bn_pol_new(a);
	bn_pol_new(b);
	bn_pol_new(c);
	bn_pol_new(d);
	bn_pol_new(m);
	
	bn_gen_prime(p, BN_BITS);
	bn_set_dig(m[0], 2);
	
	BENCH_BEGIN("bn_pol_neg") {
		bn_pol_rand_in_ring(a, p);
		BENCH_ADD(bn_pol_neg(c, a, p));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_pol_cmp") {
		bn_pol_rand_in_ring(a, p);
		BENCH_ADD(bn_pol_cmp(a, a));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_pol_mul") {
		bn_pol_rand_in_ring(a, p);
		bn_pol_rand_in_ring(b, p);
		BENCH_ADD(bn_pol_mul(c, a, b, m, p));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_pol_mul_karat") {
		bn_pol_rand_in_ring(a, p);
		bn_pol_rand_in_ring(b, p);
		BENCH_ADD(bn_pol_mul_karat(c, a, b, m, p));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_pol_sqr_basic") {
		bn_pol_rand_in_ring(a, p);
		BENCH_ADD(bn_pol_sqr_basic(c, a, m, p));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_pol_sqr_karat") {
		bn_pol_rand_in_ring(a, p);
		BENCH_ADD(bn_pol_sqr_karat(c, a, m, p));
	}
	BENCH_END;
	
	BENCH_BEGIN("bn_pol_sqr_karat_old") {
		bn_pol_rand_in_ring(a, p);
		BENCH_ADD(bn_pol_sqr_karat_old(c, a, m, p));
	}
	BENCH_END;
	
	bn_mod_pre(t, p);
	
	BENCH_BEGIN("bn_pol_sqr_u") {
		bn_pol_rand_in_ring(a, p);
		bn_mod_monty_conv(b[0], a[0], p);
		bn_mod_monty_conv(b[1], a[1], p);
		BENCH_ADD(bn_pol_sqr_u(d, b, m, p, t));
	} BENCH_END;
	
	
	BENCH_BEGIN("bn_pol_sqr_u_old") {
		bn_pol_rand_in_ring(a, p);
		bn_mod_monty_conv(b[0], a[0], p);
		bn_mod_monty_conv(b[1], a[1], p);
		BENCH_ADD(bn_pol_sqr_u_old(d, b, m, p, t));
	} BENCH_END;
	
	BENCH_BEGIN("bn_pol_rand_in_ring") {
		bn_gen_prime(p, BN_BITS);
		BENCH_ADD(bn_pol_rand_in_ring(a, p));
	} BENCH_END;
	
	bn_pol_rand_in_ring(a, p);
	BENCH_ONCE("bn_pol_mxp_basic", bn_pol_mxp_basic(c, a, p, m, p));

	BENCH_ONCE("bn_pol_mxp_slide_old", bn_pol_mxp_slide(c, a, p, m, p));

	BENCH_ONCE("bn_pol_mxp_slide = [1]", bn_pol_mxp_slide(c, a, p, m, p));
	
	bn_set_dig(t, 3);
	BENCH_ONCE("bn_pol_mxp_slide ^3", bn_pol_mxp_slide(c, a, t, m, p));
	
	BENCH_ONCE("bn_pol_mxp_basic ^3", bn_pol_mxp_basic(c, a, t, m, p));
	
	bn_set_dig(t, 6);
	BENCH_ONCE("bn_pol_mxp_slide ^6", bn_pol_mxp_slide(c, a, t, m, p));
	
	BENCH_ONCE("bn_pol_mxp_basic ^6", bn_pol_mxp_basic(c, a, t, m, p));
	
	bn_set_dig(t, 17);
	BENCH_ONCE("bn_pol_mxp_slide ^17", bn_pol_mxp_slide(c, a, t, m, p));
	
	BENCH_ONCE("bn_pol_mxp_basic ^17", bn_pol_mxp_basic(c, a, t, m, p));
	
	bn_sqr(t, p);
	bn_sub_dig(t, t, 1);
	bn_rsh(t, t, 3);
	bn_pol_rand_in_ring(a, p);
	BENCH_ONCE("[2]", bn_pol_mxp_slide(c, a, t, m, p));
	
	bn_free(t);
	bn_free(p);
	bn_pol_free(a);
	bn_pol_free(b);
	bn_pol_free(c);
	bn_pol_free(d);
	bn_pol_free(m);
}


void prime() {
	bn_t a, b;
	bn_t c[2];
	int bits;
	
	bn_null(a);
	bn_null(b);
	bn_pol_null(c);
	
	bn_new(a);
	bn_new(b);
	bn_pol_new(c);
	
	for (bits=8; bits<=BN_BITS; bits *= 2) {
		printf("\n%d BITS  -------------------------------------\n", bits);
		
		//BENCH_BEGIN("Rabin") {
		//	BENCH_ADD(bn_gen_prime(a, bits));
		//}
		//BENCH_END;
		
		//BENCH_BEGIN("SQFT") {
		//	BENCH_ADD(bn_gen_prime_sqft(a, bits));
		//}
		//BENCH_END;
		
		BENCH_ONCE("bn_gen_prime_rabin", bn_gen_prime(a, bits));
		
		BENCH_ONCE("bn_gen_prime_sqft", bn_gen_prime_sqft(a, bits));
		
		//BENCH_ONCE("bn_is_prime_sqft_subs", bn_is_prime_sqft_subs(a));
		
		//BENCH_ONCE("bn_is_prime_mr2", bn_is_prime_mr2(a, b, c));
	}
	
	bn_free(a);
	bn_free(b);
	bn_pol_free(c);
}


int main() {
	if (core_init() != STS_OK) {
		core_clean();
		return 1;
	}
	printf("BENCH == %d", BENCH);
	
	util_banner("speed tests for components", 1);
	
	perf_tests();
	
	util_banner("Benchmark for SQFT prime test:", 0);
	
	pol();
	
	util_banner("SQFT vs Miller-Rabin", 1);
	
	prime();
	
	core_clean();
	return 0;
}
